﻿#include "../../ctlComboBox.h"
#include "../../ctlHandle.h"

namespace swui
{
	bool ctlComboBox::create(ctlRoot* parent, 
		ctlPoint pos, unsigned width)
	{
		if(parent == 0 || isCreated() || !parent->isCreated()) return false; 
		std::lock_guard<decltype(_eventTrans)> gurad(
			_eventTrans.getControlEventTrans(parent));
		_control_virtual_class_end = this;
		_basic_create_(ctlRect(pos.x, pos.y, width, 1), parent);
		_controlType = ctlControlType::ctlComboBox;
		_virtual_font_create();
		_combobox_list_height = 200;
		_combobox_mouse_stay = nullptr;
		//创建 SingleEdit 控件
		_combobox_edit.create(this, ctlPoint(0, 0), 1);
		_combobox_edit.setAccess(ctlAccess::none);
		_rect.cy = _combobox_edit.getHeight();
		_combobox_edit.setRelativeSizeFormat(ctlDirection::x, _rect.cy - 1, 0, this, nullptr);
		//创建 Button 控件
		_combobox_button.create(this, ctlRect(0, 0, _rect.cy, _rect.cy));
		_combobox_button.setRelativeMoveFormat(ctlDirection::x, 
			0, 0, this, nullptr, moveAlignment::rightTop);
		_combobox_triangle_lambda = 0;
		setButtonArrowColor(0x77000000);
		_combobox_button.addLambdaEvent(ctlMouseEventType::leftPress, 
			[this](ctlRoot*, ctlMouseEvent*) { popup(); });
		//创建 List 控件
		_combobox_list.create(getParent(), ctlRect(0, 0, getWidth(), getListHeight()));
		_combobox_list.setOverflowX(ctlOverflowScroll::hide);
		_combobox_list.appendColumn(getWidth());
		_combobox_list.addLambdaEvent(ctlNotifyEventType::blur, 
			[](ctlRoot* object, ctlNotifyEvent*) { object->hide(); });
		_combobox_list.addLambdaEvent(ctlNotifyEventType::selectChange,
			[this](ctlRoot*, ctlNotifyEvent*)
			{
				_combobox_edit.setText(
					_combobox_list.getSelectedCell().ctrl->getText());
				ctlNotifyEvent ne;
				ne.info = nullptr;
				ne.eventType = ctlNotifyEventType::selectChange;
				_notify_event_(&ne);
				popdown();
			});
		_combobox_list.addLambdaEvent(ctlKeyEventType::down,
			[this](ctlRoot*, ctlKeyEvent* ke)
			{
				unsigned row;
				switch(ke->charInfo.virtualKey)
				{
				case VK_RETURN:
					row = _combobox_list.findRowIndex(_combobox_mouse_stay);
					if(_combobox_list.getSelectedRow().ctrl
						&& row == _combobox_list.getSelectedRow().index)
					{
						_combobox_edit.setText(_combobox_mouse_stay
							->getChild(0)->getText());
						popdown();
					}
					_combobox_list.setSelectedCell(row, 0);
					break;
				case VK_UP:
					row = _combobox_list.findRowIndex(_combobox_mouse_stay);
					if(_combobox_mouse_stay == nullptr)
						row = _combobox_list.getRowNumber();
					if(row != 0)
					{
						_combobox_mouse_stay = _combobox_list.getRowInfo(row - 1).ctrl;
						_combobox_list.scrollToY(row - 1);
					}
					break;
				case VK_DOWN:
					row = _combobox_list.findRowIndex(_combobox_mouse_stay);
					if(row + 1 != _combobox_list.getRowNumber())
					{
						_combobox_mouse_stay = _combobox_list.getRowInfo(row + 1).ctrl;
						_combobox_list.scrollToY(row + 1);
					}
					break;
				}
			});
		_combobox_list.addLambdaEvent(ctlNotifyEventType::list,
			[this](ctlRoot*, ctlNotifyEvent* ne)
			{
				ctlNotifyList* nl = reinterpret_cast<ctlNotifyList*>(ne->info);
				ctlColor cr;
				switch(nl->state)
				{
				case ctlNotifyList::afterInsertRow:
					nl->ctrl->setBkBorderStyle(IBackground::borderStyle::empty);
					if(ctlSingleLabel* slb = control_cast<ctlSingleLabel*>(nl->ctrl->getChild(0)))
						slb->setBkBorderStyle(IBackground::borderStyle::empty);
					nl->ctrl->addLambdaEvent(ctlMouseEventType::leftPress,
						[this](ctlRoot* object, ctlMouseEvent*)
						{
							_combobox_edit.setText(
								object->getChild(0)->getText());
							popdown();
						});
					nl->ctrl->getChild(0)->addLambdaEvent(ctlMouseEventType::enter,
						[this](ctlRoot* object, ctlMouseEvent*)
						{
							if(_combobox_mouse_stay)
							{
								_combobox_mouse_stay->setBkFillStyle(IBackground::fillStyle::empty);
								_combobox_mouse_stay->setBkFillGradientEnd(0, false);
								ctlColor cr = style_cast<ctlStyleList&>(
									_combobox_list.getStyleRef()).textColor;
								for(ctlRoot* elem : *_combobox_mouse_stay)
								{
									ctlSingleLabel* sbl = control_cast<ctlSingleLabel*>(elem);
									if(sbl) sbl->setTextColor(cr);
								}
							}
							_combobox_mouse_stay
								 = control_cast<ctlStatic*>(object->getParent());
						});
					break;
				case ctlNotifyList::redrawRow:
					if(nl->ctrl == _combobox_mouse_stay)
					{
						nl->ctrl->setBkFillStyle(IBackground::fillStyle::solid);
						ctlStyleList& dcr = style_cast<ctlStyleList&>(
							_combobox_list.getStyleRef());
						nl->ctrl->setBkFillColor(dcr.selectFill.crBegin);
						nl->ctrl->setBkFillGradientEnd(dcr.selectFill.crEnd);
						cr = dcr.selectTextColor;
					} else {
						nl->ctrl->setBkFillStyle(IBackground::fillStyle::empty);
						nl->ctrl->setBkFillGradientEnd(0, false);
						cr = style_cast<ctlStyleList&>(
							_combobox_list.getStyleRef()).textColor;
					}
					for(ctlRoot* elem : *nl->ctrl)
					{
						ctlSingleLabel* sbl = control_cast<ctlSingleLabel*>(elem);
						if(sbl) sbl->setTextColor(cr);
					}
					*nl->isAllow = false;
					break;
				} 
			});
		_combobox_list.setKeyAffect(ctlList::keyAffect::none);
		_combobox_list.hide();
		return true;
	}
	unsigned ctlComboBox::getListHeight()
	{
		return _combobox_list_height;
	}
	void ctlComboBox::setListHeight(unsigned height)
	{
		_combobox_list_height = height;
		if(isPopup()) popup();
	}
	void ctlComboBox::popdown()
	{
		_combobox_mouse_stay = nullptr;
		_combobox_list.hide();
	}
	void ctlComboBox::popup()
	{
		_combobox_list.move(getLeft(), getBottom() - 1);
		unsigned height = ctlMin(getListHeight(), 
			_combobox_list.getRowHeight());
		height = ctlMax(height, 5);
		if(_combobox_list.getHeight() != height)
			_combobox_list.size(_combobox_list.getWidth(), height);
		_combobox_list.setFocus();
		_combobox_list.show();
	}
	bool ctlComboBox::isPopup()
	{
		return _combobox_list.isShow();
	}
	ctlSingleEdit* ctlComboBox::getSingleEdit()
	{
		return &_combobox_edit;
	}
	ctlButton* ctlComboBox::getButton()
	{
		return &_combobox_button;
	}
	ctlList* ctlComboBox::getList()
	{
		return &_combobox_list;
	}
	bool ctlComboBox::insertRow(unsigned index, const ctlText& text)
	{
		if(getList()->insertRow(index, 0))
		{
			getList()->getCellInfo(index, 0).ctrl->setText(text);
			return true;
		}
		return false;
	}
	bool ctlComboBox::appendRow(const ctlText& text)
	{
		return insertRow(getList()->getRowNumber(), text);
	}
	bool ctlComboBox::removeRow(unsigned index)
	{
		return getList()->removeRow(index);
	}
	unsigned ctlComboBox::getSelectedRow()
	{
		return getList()->getSelectedRow().index;
	}
	bool ctlComboBox::setSelectedRow(unsigned index)
	{
		return getList()->setSelectedCell(index, 0);
	}
	ctlSingleLabel* ctlComboBox::getSelectedCtrl()
	{
		return getList()->getSelectedCell().ctrl;
	}
	void ctlComboBox::setButtonArrowColor(ctlColor cr)
	{
		getButton()->removeLambdaEvent(
			ctlNotifyEventType::drag, _combobox_triangle_lambda);
		_combobox_button_arrow_color = cr;
		_combobox_triangle_lambda =
			_combobox_button.addLambdaEvent(
			ctlNotifyEventType::draw, 
			createTriangleButtonHandle(
			ctlTriangleDirection::bottom, 
			0.45f, 0.38f, cr));
	}
	ctlColor ctlComboBox::getButtonArrowColor()
	{
		return _combobox_button_arrow_color;
	}
	ctlSingleLabel* ctlComboBox::getRowCtrl(unsigned index)
	{
		return getList()->getCellInfo(index, 0).ctrl;
	}
	void ctlComboBox::activeSingleEdit(bool a)
	{
		getSingleEdit()->setAccess(
			a ? ctlAccess::readWrite : ctlAccess::none);
	}
	bool ctlComboBox::isSingleEditActive()
	{
		return getSingleEdit()->getAccess() == ctlAccess::readWrite;
	}
}